package com.svimer.core.token;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 循环没有令牌的令牌桶
 * 
 * @author 姚岺坤
 *
 */
public class CirculateNoTokenBucket {

	// 默认令牌桶大小 64M Size
	private static final int DEFAULT_BUCKET_SIZE = 1024 * 1024 * 6;

	private static final int DEFAULT_ABNORMAL_TOKENS = 10;
	// 令牌桶大小
	private int tokenBucketSize;

	// 初始化令牌桶
	private ArrayBlockingQueue<Byte> tokenQueue = new ArrayBlockingQueue<Byte>(DEFAULT_BUCKET_SIZE);
	// 异常令牌
	private List<Token> abnormalTokens = new ArrayList<Token>(DEFAULT_ABNORMAL_TOKENS);

	// 重入锁 true时为公平锁，是false为非公平锁
	private ReentrantLock lock = new ReentrantLock(true);

	// 令牌占位字符，char表示英文字母：在uft8编码下占一个字节；在GBK编码下还是占2个字节；
	private static final byte A_CHAR = 'a';

	public CirculateNoTokenBucket() {

	}

	public CirculateNoTokenBucket(int tokenBucketSize) {
		this.tokenBucketSize = tokenBucketSize;
		addTokens(tokenBucketSize);
	}

	public void addTokens(Integer tokenNum) {
		// 若是桶已经满了，就不再加入新的令牌
		for (int i = 0; i < tokenNum; i++) {
			// 向令牌桶存放令牌占位字符
			// offer(E e)：表示如果可能的话，将 e 加到 BlockingQueue 里，即如果 BlockingQueue
			// 可以容纳，则返回 true，否则返回 false
			tokenQueue.offer(Byte.valueOf(A_CHAR));

		}
	}

	public void start() {
		// 初始化桶队列大小
		if (tokenBucketSize != 0) {
			tokenQueue = new ArrayBlockingQueue<Byte>(tokenBucketSize);
		}

	}

	public CirculateNoTokenBucket build() {
		start();
		addTokens(tokenBucketSize);
		return this;
	}

	public boolean getTokens(int needTokenNum) {
		// Preconditions.checkNotNull(dataSize);
		// Preconditions.checkArgument(isStart, "please invoke start method
		// first !");

		final ReentrantLock lock = this.lock;
		lock.lock();
		try {
			boolean result = needTokenNum <= tokenQueue.size();// 是否存在足够的令牌数量
			System.out.println("needTokenNum : tokenQueue.size() = " + needTokenNum + " : " + tokenQueue.size());
			if (!result) {
				return false;
			}

			int tokenCount = 0;
			for (int i = 0; i < needTokenNum; i++) {
				Byte token = tokenQueue.poll();
				if (token != null) {
					tokenCount++;
				}
			}

			return tokenCount == needTokenNum;
		} finally {
			lock.unlock();
		}

	}

	public static CirculateNoTokenBucket newBuilder() {
		return new CirculateNoTokenBucket();
	}

	public CirculateNoTokenBucket tokenBucketSize(int tokenBucketSize) {
		this.tokenBucketSize = tokenBucketSize;
		return this;
	}

	public int getTokenQueueRemainingCapacity() {
		return tokenQueue.remainingCapacity();
	}

	public int getAbnormalTokensSize() {
		return abnormalTokens.size();
	}

	// 降序
	public void sortListDesc() {
		Collections.sort(abnormalTokens, new Comparator<Token>() {
			public int compare(Token o1, Token o2) {
				if (null == o1.getTimeDifference()) {
					return 1;
				}
				if (null == o2.getTimeDifference()) {
					return -1;
				}
				return o2.getTimeDifference().compareTo(o1.getTimeDifference());
			}
		});

	}

	public void addAbnormalToken(Token token) {
		synchronized (abnormalTokens) {
			sortListDesc();
			if (abnormalTokens.size() >= DEFAULT_ABNORMAL_TOKENS) {
				if (token.getTimeDifference() > abnormalTokens.get(DEFAULT_ABNORMAL_TOKENS - 1).getTimeDifference()) {
					abnormalTokens.remove(DEFAULT_ABNORMAL_TOKENS - 1);
					abnormalTokens.add(token);
				} 
				addTokens(1);
			}else{
				
				abnormalTokens.add(token);
			}
		}

	}

	@Override
	public String toString() {
		return "CirculateNoTokenBucket [abnormalTokens=" + abnormalTokens + "]";
	}

}
